package com.microsoft.ocr.mlkit;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import com.google.android.gms.tasks.Task;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.mlkit.vision.barcode.BarcodeScanner;
import com.google.mlkit.vision.barcode.BarcodeScanning;
import com.google.mlkit.vision.barcode.common.Barcode;
import com.google.mlkit.vision.common.InputImage;
import com.microsoft.azure.storage.CloudStorageAccount;
import com.microsoft.azure.storage.blob.CloudBlobClient;
import com.microsoft.azure.storage.blob.CloudBlobContainer;
import com.microsoft.azure.storage.blob.CloudBlobDirectory;
import com.microsoft.azure.storage.blob.CloudBlockBlob;
import com.microsoft.azure.storage.blob.ListBlobItem;
import com.microsoft.ocr.mlkit.databinding.ActivityMainBinding;
import com.microsoft.ocr.mlkit.utils.ResultBean;

import java.io.File;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";


    /**
     * 登录的账户和token
     */
    public static final String storageConnectionString = "DefaultEndpointsProtocol=https;AccountName=qiduandev;AccountKey=SxuGQXQJDAF0g3qOZJd0WeH32yy7cV7lNjRqFZwq2XcGY/X+e6WMBaN8DCafUTIoHWWJsx+ps05LYTFTCNvFPA==;EndpointSuffix=core.windows.net";
    /**
     * Blob容器
     */
    private CloudBlobContainer container;
    /**
     * Base64编码器
     */
    private Base64.Encoder encoder = Base64.getEncoder();
    // 用来解析
    private Gson gson = new GsonBuilder().disableHtmlEscaping().create();

    /**
     * 线程池，用来下载图片、识别图片
     */
    private Executor singleExecutor = Executors.newSingleThreadExecutor();
    private Handler uiHandler = new Handler(Looper.getMainLooper());
    // 存储下载的图片
    private String DIR = "blob_image";

    private ActivityMainBinding binding;
    private boolean isInit = false;

    @SuppressLint("SetTextI18n")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        binding.btnDown.setOnClickListener(view -> init());
        binding.btnChoose.setOnClickListener(view -> start());
    }

    @SuppressLint("CheckResult")
    private void start() {
        if (!isInit) {
            tips("请先初始化");
            return;
        }
        binding.textView.setText("Start");
        binding.btnChoose.setEnabled(false);
        singleExecutor.execute(() -> {
            List<CloudBlockBlob> urls = downLoadFromBlob();
            AtomicInteger i = new AtomicInteger(-1);
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    if (i.incrementAndGet() < urls.size()) {
                        CloudBlockBlob blob = urls.get(i.get());
                        downLoadPicture(blob, this);
                    } else {
                        Log.d(TAG, "已经完成");
                        tips("已经完成");
                        uiHandler.post(() -> {
                            binding.textView.setText("已经完成");
                            binding.btnChoose.setEnabled(true);
                        });
                    }
                }
            };
            runnable.run();
        });
    }

    private void init() {
        singleExecutor.execute(() -> {
            try {
                // 创建账户
                CloudStorageAccount account = CloudStorageAccount.parse(storageConnectionString);
                // 创建Blob客户端
                CloudBlobClient blobClient = account.createCloudBlobClient();
                // 获取容器
                container = blobClient.getContainerReference("dev");
                // 如果容器不存在就创建
                if (container.createIfNotExists()) {
                    Log.d(TAG, "CreateCloudBlobContainer");
                }
                isInit = true;
                Log.d(TAG, "初始化完成");
                tips("初始化完成");
                uiHandler.post(() -> {
                    binding.textView.setText("初始化完成");
                    binding.btnDown.setEnabled(false);
                });
            } catch (Exception e) {
                e.printStackTrace();
                printException(e);
            }
        });
    }

    /**
     * 从Blob下载图片的url
     */
    private List<CloudBlockBlob> downLoadFromBlob() {
        List<CloudBlockBlob> urls = new ArrayList<>();
        try {
            // 获取权限(不需要权限)
            //BlobContainerPermissions containerPermissions = new BlobContainerPermissions();
            //containerPermissions.setPublicAccess(BlobContainerPublicAccessType.CONTAINER);
            //container.uploadPermissions(containerPermissions);

            // 遍历并下载
            for (ListBlobItem blobItem : container.listBlobs()) {
                // 是个文件夹，则再次遍历
                if (blobItem instanceof CloudBlobDirectory) {
                    CloudBlobDirectory blobDirectory = (CloudBlobDirectory) blobItem;
                    // 只解析image/目录下的
                    if ("image/".equals(blobDirectory.getPrefix())) {
                        Iterable<ListBlobItem> listBlobItems = blobDirectory.listBlobs();
                        for (ListBlobItem listBlobItem : listBlobItems) {
                            addBlobRecur(listBlobItem, urls);
                        }
                    }
                }
            }

            // Delete the blobs
            //blob1.deleteIfExists();
            //blob2.deleteIfExists();
            //blob3.deleteIfExists();
            // Delete the container
            //container.deleteIfExists();
        } catch (Throwable t) {
            printException(t);
        }
        return urls;
    }

    /**
     * 递归添加blobItem的url
     */
    private void addBlobRecur(ListBlobItem blobItem, List<CloudBlockBlob> urls) {
        if (blobItem instanceof CloudBlockBlob) { // 如果是blob，直接添加
            CloudBlockBlob retrievedBlob = (CloudBlockBlob) blobItem;
            Log.d(TAG, "blobItem, name=" + retrievedBlob.getName() + ", url=" + retrievedBlob.getUri());
            urls.add(retrievedBlob);
        } else if (blobItem instanceof CloudBlobDirectory) { // 如果是文件夹，则遍历递归
            try {
                Iterable<ListBlobItem> listBlobs = ((CloudBlobDirectory) blobItem).listBlobs();
                for (ListBlobItem item : listBlobs) addBlobRecur(item, urls);
            } catch (Exception e) {
                printException(e);
            }
        }
    }

    private void downLoadPicture(CloudBlockBlob blob, Runnable complete) {
        Log.d(TAG, "start download: " + blob.getUri());
        long start = System.currentTimeMillis();
        //final FutureTarget<Bitmap> future = GlideApp.with(MainActivity.this).asBitmap().load(path).submit();
        try {
            // 下载到本地文件
            File file = new File(GetStoragePath(DIR), blob.getName().replace("/", "_"));
            if (!file.exists()) {
                Log.d(TAG, "create file: " + file.createNewFile());
            }
            blob.downloadToFile(file.getAbsolutePath());
            Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
            InputImage image = InputImage.fromBitmap(bitmap, 0);
            BarcodeScanner scanner = BarcodeScanning.getClient();
            Task<List<Barcode>> result = scanner.process(image).addOnSuccessListener(barcodes -> {
                Log.d(TAG, "onSuccess " + Thread.currentThread().getName());
                // 成功 解析结果
                analyze(barcodes, blob.getName(), complete, start);
            }).addOnFailureListener(e -> {
                // 失败
                Log.d(TAG, "onFailure: exception = " + e);
                tips("失败: " + e);
                // 执行回调
                singleExecutor.execute(complete);
            });
        } catch (Exception e) {
            // 执行回调
            complete.run();
            printException(e);
            e.printStackTrace();
        }
    }

    /**
     * 解析结果拼成json
     *
     * @param barcodes 得到实际的结果
     */
    private void analyze(List<Barcode> barcodes, String name, Runnable complete, long start) {
        if (barcodes.isEmpty()) {
            Log.d(TAG, "barcodes is empty");
            singleExecutor.execute(complete);
            return;
        }
        singleExecutor.execute(() -> {
            // 解析成只包含三个值的 json
            List<ResultBean> lists = new ArrayList<>();
            for (Barcode barcode : barcodes) {
                lists.add(new ResultBean(barcode.getBoundingBox(), barcode.getFormat(), barcode.getRawValue(), encoder.encodeToString(barcode.getRawBytes())));
            }
            String json = gson.toJson(lists);
            Log.d(TAG, "analyze result: " + json);
            uploadToBlob(json, name, complete, start);
        });
    }

    /**
     * 将结果上传到Blob
     */
    private void uploadToBlob(String json, String name, Runnable complete, long start) {
        try {
            CloudBlobDirectory results = container.getDirectoryReference("results");
            CloudBlockBlob blob = results.getBlockBlobReference(name.substring(0, name.lastIndexOf(".")));
            blob.uploadText(json);
            Log.d(TAG, "uploadToBlob success: " + json + "\n, cost time: " + (System.currentTimeMillis() - start) + "ms");
            complete.run();
        } catch (Exception e) {
            complete.run();
            printException(e);
        }
    }

    private void tips(String msg) {
        uiHandler.post(() -> Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show());
    }

    public void printException(Throwable t) {
        Log.d(TAG, "Exception: " + t.getMessage());
    }


    /**
     * 获取可用的path
     */
    public String GetStoragePath(String dir) {
        Context context = this;
        String path = "";
        if (android.os.Environment.MEDIA_MOUNTED.equals(android.os.Environment.getExternalStorageState()) || !android.os.Environment.isExternalStorageRemovable()) {
            File externalFilesDir = context.getExternalFilesDir(dir);
            if (externalFilesDir != null) {
                path = externalFilesDir.getPath();
            } else {
                path = context.getFilesDir().getPath() + File.separator + dir;
            }
        } else {
            path = context.getFilesDir().getPath() + File.separator + dir;
        }
        Log.d(TAG, "Get StoragePath " + path);
        return path;
    }

}